/**
 * 
 */
package simulation;

import java.util.ArrayList;
import java.util.HashSet;

/**
 * @author aclayton
 *
 */
public class MazeGenerator {
	private Map map;
	
	
	public MazeGenerator(Map map){
		this.map = map;
	}
	
	public HashSet<Point> getNeighboringCells(Rect mazeBox, Point pt){
		HashSet<Point> neighbors = new HashSet<Point>();
		
		Point temp = new Point(pt.getX()+1,pt.getY());
		if(mazeBox.pointInBox(temp))
			neighbors.add(temp);
		
		temp = new Point(pt.getX()-1,pt.getY());
		if(mazeBox.pointInBox(temp))
			neighbors.add(temp);
		
		temp = new Point(pt.getX(),pt.getY()+1);
		if(mazeBox.pointInBox(temp))
			neighbors.add(temp);
		
		temp = new Point(pt.getX(),pt.getY()-1);
		if(mazeBox.pointInBox(temp))
			neighbors.add(temp);
		
		return neighbors;
		
	}
	
	
	public void generatePrimMaze(double wallsize){
		int mazewidth = (int)(map.getLength()/wallsize);
		int mazeheight = (int)(map.getWidth()/wallsize);
		Rect mazeBox = new Rect(0, mazewidth-2, mazeheight-2, 0);
		int[][] mazemap = new int[mazewidth][mazeheight];
		
		for(int a = 0; a < mazewidth; a++){
			for(int b = 0; b < mazeheight; b++)
				mazemap[a][b] = 1;
		}
		
		mazemap[1][1] = 0;
		HashSet<Point> wallList = new HashSet<Point>();
		wallList.addAll(getNeighboringCells(mazeBox,new Point(1,1)));
		
		while(!wallList.isEmpty()){
			
			Point currentWall = wallList.iterator().next();
			
			
			HashSet<Point> neighboringPts = getNeighboringCells(mazeBox,currentWall);
			Point neighboringPassage = new Point();
			for(Point temp : neighboringPts){
				if(mazemap[(int)temp.getX()][(int)temp.getY()] == 0){
					neighboringPassage = temp;
					break;
				}
			}
			
			double oppositeX = (currentWall.getX()-neighboringPassage.getX())+currentWall.getX();
			double oppositeY = (currentWall.getY()-neighboringPassage.getY())+currentWall.getY();
			Point opposite = new Point(oppositeX, oppositeY);
			
			if(!mazeBox.pointInBox(opposite)){
				wallList.remove(currentWall);
				continue;
			}
			
			if(mazemap[(int)oppositeX][(int)oppositeY] == 0){
				wallList.remove(currentWall);
			} else {
				mazemap[(int)currentWall.getX()][(int)currentWall.getY()] = 0;
				mazemap[(int)oppositeX][(int)oppositeY] = 0;
				HashSet<Point> oppositeNieghbors = getNeighboringCells(mazeBox,opposite);
				for(Point oppositeNieghbor : oppositeNieghbors){
					if(mazemap[(int)oppositeNieghbor.getX()][(int)oppositeNieghbor.getY()] == 1)
						wallList.add(oppositeNieghbor);
				}
				wallList.remove(currentWall);
			}
		}
		for(int a = 0; a < mazeheight; a++){
			String temp = "";
			for(int b = 0; b < mazewidth; b++)
				temp = temp + mazemap[b][a] + ", ";
			System.out.println(temp);
		}
		
		for(int a = 0; a < mazeheight; a++){
			for(int b = 0; b < mazewidth; b++){
				if(mazemap[a][b] == 1){
					Point p1 = new Point(a*wallsize, b*wallsize);
					Point p2 = new Point((a+1)*wallsize, b*wallsize);
					Point p3 = new Point(a*wallsize, (b+1)*wallsize);
					Point p4 = new Point((a+1)*wallsize, (b+1)*wallsize);
					
					map.addObstacle(new Obstacle(p1,p2,p4));
					map.addObstacle(new Obstacle(p1,p3,p4));
				}
					
			}
		}
			
	}
	
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		if(args.length != 4){
			System.out.println("Usage");
			System.out.println("MazeGenerator mapwidth mapheight wallsize savelocation");
			System.exit(0);
		}
		
		double width = Double.parseDouble(args[0]);
		double height = Double.parseDouble(args[1]);
		double wallsize = Double.parseDouble(args[2]);
		String saveLocation = args[3];
		
		System.out.println(width);
		System.out.println(height);
		System.out.println(wallsize);
		System.out.println(saveLocation);
		
		Map m = new Map(width,height);
		MazeGenerator gen = new MazeGenerator(m);
		
		gen.generatePrimMaze(wallsize);
		m.saveToFile(saveLocation);

	}

}
